
#pragma once

#include "atr/containers/capacity.hpp"
#include "atr/containers/iterators.hpp"

namespace atr {

/**
 * @brief   Helps initializing metacontainers with repeating sequence
 * @details This struct helps with initializing container when wanted sequence
 *          can be descibe as repeated pattern.
 *
 * @param   template <class ...> Base Sequence type You want to initialize
 * @param   Count Number of repeations o pattern
 * @param   typename ... Types pattern
 *
 */
template <template <class ...> class Base,
          unsigned long Count,
          typename ... Types>
    struct initializer_list;

/**
 * @brief   Namespace only for internal use of atr library
 * @details Please don't use this namespace outside the atr library.
 *          IF you REALLY need to - do it with special care.
 */
namespace __ {

/**
 * @brief   Helper for initializer_list with memory of base pattern
 * @details This struct helps initializer_list by handling tract of current AND
 *          original sequence
 *
 * @tparam  Base sequence
 * @tparam  Actual sequence
 * @tparam  long Count remaining count
 */
template <typename Base, typename Actual, unsigned long Count>
    struct initializer_list_proxy;

/**
 * @brief   Helper for initializer_list with memory of base pattern - terminator
 * @details This struct helps initializer_list by handling tract of current AND
 *          original sequence. This case is the last one - terminator - of
 *          reccurention.
 *
 * @tparam  Base container
 * @tparam  BaseTypes sequence
 * @tparam  Actual container
 * @tparam  ActualTypes sequence
 */
template <template <class ...> class Base, typename ... BaseTypes,
          template <class ...> class Actual, typename ... ActualTypes>
struct initializer_list_proxy<Base<BaseTypes...>,
                              Actual<ActualTypes...>,
                              0>
    : public __::__capacity<>
    , public __::__iterators<Base>
    { using type = Base<>; };

/**
 * @brief   Helper for initializer_list with memory of base pattern - terminator
 * @details This struct helps initializer_list by handling tract of current AND
 *          original sequence. This case is the last one - terminator - of
 *          reccurention.
 *
 * @tparam  Base container
 * @tparam  BaseTypes sequence
 * @tparam  Actual container
 * @tparam  ActualTypes sequence
 */
template <template <class ...> class Base, typename ... BaseTypes,
          template <class ...> class Actual, typename ... ActualTypes>
struct initializer_list_proxy<Base<BaseTypes...>,
                              Actual<ActualTypes...>,
                              1>
    : public __::__capacity<ActualTypes...>
    , public __::__iterators<Base, ActualTypes...>
    { using type = Base<ActualTypes...>; };

/**
 * @brief   Helper for initializer_list with memory of base pattern - terminator
 * @details This struct helps initializer_list by handling tract of current AND
 *          original sequence. This case is recurrenction.
 *
 * @tparam  Base container
 * @tparam  BaseTypes sequence
 * @tparam  Actual container
 * @tparam  ActualTypes sequence
 * @tparam  Count remaining
 */
template <template <class ...> class Base, typename ... BaseTypes,
          template <class ...> class Actual, typename ... ActualTypes,
          unsigned long Count>
struct initializer_list_proxy<Base<BaseTypes...>,
                              Actual<ActualTypes...>,
                              Count>
    : public initializer_list_proxy<Base<BaseTypes...>,
                                    Actual<ActualTypes..., BaseTypes...>,
                                    Count-1>
    {};

} // namespace __

/**
 * @brief   Helps initializing metacontainers with repeating sequence
 * @details This struct helps with initializing container when wanted sequence
 *          can be descibe as repeated pattern.
 *
 * @param   template <class ...> Base Sequence type You want to initialize
 * @param   Count Number of repeations o pattern
 * @param   typename ... Types pattern
 *
 */
template <template <class ...> class Base,
          unsigned long Count,
          typename ... Types>
struct initializer_list
    : public __::initializer_list_proxy<Base<Types...>, Base<Types...>, Count>
    {};

} // namespace atr